import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { BaseHttpService } from '../../shared/services/baseHttp.service';
import { HttpClient, HttpParams, HttpEvent, HttpHeaders } from '@angular/common/http';
import { Profile } from './models/profile.model';
import { TokenModel } from './models/token.model';
import { Claims } from '../../shared/models/claims.model';
import { StorageService } from '../../shared/services/storage.service';
import { tap } from 'rxjs/operators';

/**
 * Login main service
 *
 * Author: Sorin Spiru, Andrei Istrate
 * Date: 13.01.2018
 */
@Injectable()
export class AuthenticationService extends BaseHttpService {
    constructor(private http: HttpClient) {
        super();
    }

    /**
     * Base login method. Used by actual login and token refresh
     * @param params Login credentials
     */
    public requestLogin(params: HttpParams): Observable<HttpEvent<TokenModel>> {
        return this.http.post(this.serverUrl + 'auth/token', params).catch((err, caught) => of(err));
    }

    /**
     * Login method
     * @param username Username
     * @param password Password
     */
    public login(username: string, password: string): Observable<HttpEvent<TokenModel>> {
        let params = new HttpParams();
        params = params.set("grant_type", "password")
            .set("username", username)
            .set("password", password)
            .set("client_id", "clientId1");

        return this.requestLogin(params).pipe(tap(
            response => this.saveToken(response)
        ));
    }

    public ipLogin(): Observable<HttpEvent<TokenModel>> {
        return this.http.post(this.serverUrl + 'accountsserv/api/account/iplogin', null, { observe: 'response' })
            .map(function (o) { return { body: o.body, headers: o.headers } })
            .catch((err, caught) => of(err));
    }

    /**
     * Get user claims and save them to local storage
     */
    public permissions(): Observable<Claims[]> {
        return this.http.get<Claims[]>(this.serverUrl + 'claimsserv/api/v1/claims').pipe(tap(
            response => localStorage.setItem('sust:a:claims', JSON.stringify(response))
        ));
    }

    /**
     * Get user info and save it to local storage
     */
    public profile(): Observable<Profile> {
        return this.http.post<Profile>(this.serverUrl + 'accountsserv/api/account/profile', null).pipe(tap(
            response => localStorage.setItem('sust:a:user', JSON.stringify(response))
        ));
    }

    /**
     * Delete user data from local storage on logout
     */
    public logout(): void {
        localStorage.removeItem('sust:a');
        localStorage.removeItem('sust:a:claims');
        localStorage.removeItem('sust:a:user');
    }

    /**
     * Post email for password reset
     * @param email User email to receive password reset info
     */
    public resetPassword(email: string) {
        let headers = new HttpHeaders();
        headers = headers.set("Content-Type", 'application/json');
        return this.http.post(this.serverUrl + 'accountsserv/api/account/forgotPassword', "'" + email + "'", { headers: headers, responseType: 'text' });
    }

    public changePassword(email: string, password: string) {
        return this.http.post(this.serverUrl + 'accountsserv/api/account/setPassword', { username: email, password: password }, { responseType: 'text' });
    }

    public refreshToken(): Observable<HttpEvent<TokenModel>> {
        let auth = StorageService.get().authData;
        let params = new HttpParams();
        params = params.set("grant_type", "refresh_token")
            .set("refresh_token", auth.refresh_token)
            .set("client_id", "clientId1");
        return this.requestLogin(params);
    }

    public saveToken(response: any): void {
        response['loginTime'] = new Date();
        localStorage.setItem('sust:a', JSON.stringify(response));
    }
}
